package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func main() {
	promise_all()
	promise_any()
	promise_any_v2()

	// 使用
	res := PromiseAll(3, []func() int{
		func() int { time.Sleep(1 * time.Second); return 1 },
		func() int { time.Sleep(2 * time.Second); return 2 },
		func() int { time.Sleep(3 * time.Second); return 3 },
	})
	fmt.Println(res) // [1 2 3]  —— 3 秒后一次性拿到
}
func promise_all() {
	var awaitGroup sync.WaitGroup
	awaitGroup.Add(2)
	// 启动一个goroutine向ch1发送数据
	go func() {
		defer awaitGroup.Done()
		fmt.Println("goroutine 1 running")

	}()

	// 启动另一个goroutine向ch2发送数据
	go func() {
		defer awaitGroup.Done()
		fmt.Println("goroutine 2 running")
	}()

	awaitGroup.Wait()
	fmt.Println("All goroutine is done")
}
func promise_any() {
	ch1 := make(chan interface{})
	ch2 := make(chan interface{})

	// 启动一个goroutine向ch1发送数据
	go func() {
		fmt.Println("goroutine 1 running")
		ch1 <- "11"

	}()

	// 启动另一个goroutine向ch2发送数据
	go func() {
		fmt.Println("goroutine 2 running")
		ch2 <- "22"
	}()

	select {
	case res := <-ch1:
		fmt.Println("Received from ch1:", res)
	case res := <-ch2:
		fmt.Println("Received from ch2:", res)
	}
}
func promise_any_v2() {
	//	缓冲为 1 的 race 只能装下第一个结果，
	// 后到的 goroutine 在 default 分支里直接 放弃写入、退出，
	// 于是 main goroutine 只被第一个结果“唤醒”，其它 goroutine 悄然结束，不会阻塞
	race := make(chan string, 1) // 缓冲 1，保证不阻塞

	for _, id := range []string{"g1", "g2"} {
		go func(name string) {
			fmt.Println(name, "running")
			time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) // 模拟随机耗时
			select {
			case race <- name + "-result":
			default: // 已被抢先，直接退出
			}
		}(id)
	}

	first := <-race
	fmt.Println("first resolved:", first)

}
func PromiseAll(count int, jobs []func() int) []int {
	results := make(chan int, count) // 缓冲 = 任务数，保证不阻塞

	for _, job := range jobs {
		go func(f func() int) {
			results <- f() // 每个 goroutine 必然能写进去
		}(job)
	}

	// 收齐全部结果
	out := make([]int, 0, count)
	for i := 0; i < count; i++ {
		out = append(out, <-results)
	}
	return out
}
